%include "io.inc"

section .data
msg db "please input two numbers divided by a blank:", 0h

section .bss
input: resb 255
sum: resb 255
temp_sum: resb 255
num1: resb 255
num2: resb 255
num1_for_mul: resb 255
addtimes: resb 1
mul_result: resb 255
carry: resb 1   ;进位
len_num1: resb 4
len_num2: resb 4
len_sum: resb 4
temp_len1: resb 4
temp_len2: resb 4
temp_len1_for_mul: resb 4
temp_len2_for_mul: resb 4
line_split: resb 1


 
section .text
global CMAIN
CMAIN:
    mov ebp, esp; for correct debugging
    ;PRINT_STRING msg
    ;NEWLINE
    mov eax, line_split
    mov byte[eax], 0ah
    mov eax, msg
    mov ecx, msg
    call print_res
    mov dword[len_num1], 0
    mov dword[len_num2], 0
    ;获取输入的数据
    mov eax, 3
    mov ebx, 0
    mov ecx, input
    mov edx, 255
    int 80h
    
    mov edi, 0  ;counter
    mov eax, num1
    

;获取第一个数字
getnum1:
    mov ebx, ecx
    cmp byte[ecx], " "
    je createnum1
    inc edi
    inc ecx
    ;mov dword[len_num1], edi
    add dword[len_num1], 1
    jmp getnum1

;赋值第一个数字
createnum1:
    dec ebx ;因为在getnum1中跳转到该方法时byte[ebx]为“ ”，所以先要减1
    cmp edi, 0
    je beforecreate
    mov dl, byte[ebx]
    mov byte[eax+edi-1], dl ;num1
    dec edi
    jmp createnum1

beforecreate:
    mov edi, dword[len_num1]
    mov eax, num1_for_mul
    
createnum1_for_mul:
    cmp edi, 0
    je init_eax
    mov dl, byte[ebx+edi]
    mov byte[eax+edi-1], dl ;num1_for_mul
    dec edi
    jmp createnum1_for_mul
    
init_eax:
    mov eax, num2
    
getnum2:
    inc ecx
    cmp byte[ecx], 10
    je createnum2
    inc edi
    add dword[len_num2], 1
    jmp getnum2
    
createnum2:
    dec ecx
    cmp edi, 0
    je addfunc
    mov dl, byte[ecx]
    mov byte[eax+edi-1], dl
    dec edi
    jmp createnum2
    
addfunc:
    mov eax, dword[len_num1]
    mov dword[temp_len1], eax
    mov eax, dword[len_num2]
    mov dword[temp_len2], eax
    mov eax, num1
    mov ebx, num2
    mov dword[len_sum], 0
    mov esi, dword[len_num1]
    cmp esi, dword[len_num2]
    jb beforeadd
f1:    mov edi, temp_sum
    mov byte[carry], 0   ;初始化进位0
    jmp addloop
    
beforeadd:  ;num1比num2位数少的情况
    mov eax, num2
    mov ebx, num1
    mov ecx, dword[len_num1]
    mov esi, dword[len_num2]
    mov dword[temp_len1], esi
    mov dword[temp_len2], ecx
    jmp f1
    
addloop:
    cmp dword[temp_len1], 0    ;第一个数字的最高位已经进行过运算时跳转（加法循环结束）
    je addfinal
    mov esi, dword[temp_len1]
    mov cl, byte[eax+esi-1]
    sub cl, 48
    add cl, byte[carry]
    mov esi, dword[temp_len2]
    mov dl, byte[ebx+esi-1]
    sub dl, 48
    cmp dword[temp_len2], 0    ;如果第二个数字最高位已经加过，那么接下来都是用0和第一个数字加
    jna set_dl_0
f2:    add cl, dl
    ;mov byte[carry], 0
    cmp cl, 10  ;如果加起来的数字大于10，说明有进位
    jnb withcarry
    
nocarry:
    mov byte[carry], 0   ;进位0
    add cl, 48  ;+48
    mov byte[edi], cl   ;保存在temp_sum所在的内存
    inc edi
    add dword[len_sum], 1
    sub dword[temp_len1], 1
    sub dword[temp_len2], 1
    jmp addloop
    
withcarry:
    mov byte[carry], 1   ;进位1
    sub cl, 10  ;加起来的数字减10
    add cl, 48  ;+48
    mov byte[edi], cl   ;保存在temp_sum所在的内存
    inc edi
    add dword[len_sum], 1
    sub dword[temp_len1], 1
    sub dword[temp_len2], 1
    jmp addloop
    
set_dl_0:
    mov dl, 0
    mov dword[temp_len2], 1
    jmp f2

addfinal:
    cmp byte[carry], 1
    je finalcarry
f3:    mov eax, sum
    mov ebx, len_sum
    dec edi
    jmp reverse_addresult   ;内存中加法的结果是从低位到高位存的，所以打印前先进行反转处理

reverse_addresult:
    mov dl, byte[edi]
    mov byte[eax], dl
    inc eax
    dec edi
    sub dword[len_sum], 1
    cmp dword[len_sum], 0
    je print_addresult
    
    jmp reverse_addresult
    
finalcarry:
    mov byte[edi], 49   ;最高位加起来有进位的时候，sum的最高位为1
    inc edi
    add dword[len_sum], 1
    ;  最后将carry位置0
    mov byte[carry], 0
    jmp f3
    
print_addresult:
    ;PRINT_STRING sum
    ;NEWLINE
    mov eax, sum
    mov ecx, sum
    call print_res
    jmp beforemul
;testprint:
;   PRINT_STRING num1
;    NEWLINE
;    PRINT_STRING num2
;    NEWLINE

clear_temp_sum:
    mov ebx, temp_sum
    cmp byte[ebx], ""
    jne clear
    ret
    
clear:
    mov byte[ebx], ""
    inc ebx
    jmp clear_temp_sum
        
;乘法运算前先将temp结果置为0,并获取2个数字的长度
beforemul:
    push eax
    mov byte[mul_result], "0"
    mov eax, dword[len_num1]
    mov dword[temp_len1_for_mul], eax
    mov eax, dword[len_num2]
    mov dword[temp_len2_for_mul], eax
    pop eax
    ;mov byte[carry], "0"
    call clear_temp_sum
    
;乘法思路：ebx指向被乘数，ecx指向乘数，计算的时候从低位开始读乘数的每一位，作为加法循环次数，每读一位，被乘数最后一位补0
mulfunc:
    mov ebx, num1_for_mul
    mov ecx, num2
    ;被乘数为0
    cmp byte[ebx], "0"
    je  mulzero
    ;乘数为0
    cmp byte[ecx], "0"
    je mulzero
    jmp mulloop
    
mulloop:
    
    ;乘数每一位都被读完时结束
    
    cmp dword[temp_len2_for_mul], 0
    je mulfinal
    mov edi, dword[temp_len2_for_mul]
    cmp byte[ecx+edi-1], 48 ;乘数的某一位
    push ecx
    je m4
    ;cmp byte[ecx+edi-1], 49
    ;je case_one
    push eax
    mov al, byte[ecx+edi-1]
    mov byte[addtimes], al
    pop eax
    mov eax, num1_for_mul
    ;sub byte[addtimes], 48
    push edi
    push ecx
m1:
    pop edi
    call beforeloop
    push ebx
    call clear_temp_sum
    pop ebx
    sub byte[addtimes], 1
    cmp byte[addtimes], 47
    push edi
    ;sub byte[addtimes], 1
    mov edi, temp_sum
    jnz addloop_for_mul
    
    ;加法循环结束
m4:    pop ecx
    sub dword[temp_len2_for_mul], 1
    add dword[temp_len1_for_mul], 1
    mov eax, num1_for_mul
    mov ebx, dword[temp_len1_for_mul]
    mov byte[eax+ebx-1], "0"    ;num1补0
    push ebx
    call clear_temp_sum
    pop ebx
    pop edi
    jmp mulloop
    
; 被乘数或者乘数为0的时候调用，直接将结果置为0
mulzero:
    mov byte[mul_result], "0"
    jmp print_mulresult


mulfinal:    
    jmp print_mulresult
print_mulresult:
    mov eax, mul_result
    mov ecx, mul_result
    call print_res 
    ;PRINT_STRING mul_result
    ;NEWLINE
    jmp exit
    
    
addloop_for_mul:
    cmp dword[temp_len1], 0    ;第一个数字的最高位已经进行过运算时跳转（加法循环结束）
    je addfinal_mul
    mov esi, dword[temp_len1]
    mov cl, byte[eax+esi-1]
    sub cl, 48
    add cl, byte[carry]
    mov esi, dword[temp_len2]
    mov dl, byte[ebx+esi-1]
    sub dl, 48
    cmp dword[temp_len2], 0    ;如果第二个数字最高位已经加过，那么接下来都是用0和第一个数字加
    jna set_dl_0_mul
m2:    add cl, dl
    ;mov byte[carry], 0
    cmp cl, 10  ;如果加起来的数字大于10，说明有进位
    jnb withcarry_mul
    
nocarry_mul:
    mov byte[carry], 0   ;进位0
    add cl, 48  ;+48
    mov byte[edi], cl   ;保存在temp_sum所在的内存
    inc edi
    add dword[len_sum], 1
    sub dword[temp_len1], 1
    sub dword[temp_len2], 1
    jmp addloop_for_mul
    
withcarry_mul:
    mov byte[carry], 1   ;进位1
    sub cl, 10  ;加起来的数字减10
    add cl, 48  ;+48
    mov byte[edi], cl   ;保存在temp_sum所在的内存
    inc edi
    add dword[len_sum], 1
    sub dword[temp_len1], 1
    sub dword[temp_len2], 1
    jmp addloop_for_mul
    
set_dl_0_mul:
    mov dl, 0
    mov dword[temp_len2], 1
    jmp m2

addfinal_mul:
    cmp byte[carry], 1
    je finalcarry_mul
m3:    mov eax, mul_result
    mov ebx, len_sum
    dec edi
    jmp reverse_addresult_mul

reverse_addresult_mul:
    mov dl, byte[edi]
    mov byte[eax], dl
    inc eax
    dec edi
    sub dword[len_sum], 1
    cmp dword[len_sum], 0
    je m1
    jmp reverse_addresult_mul
    
finalcarry_mul:
    mov byte[edi], 49   ;最高位加起来有进位的时候，sum的最高位为1
    inc edi
    add dword[len_sum], 1
    ;  最后将carry位置0
    mov byte[carry], 0
    jmp m3
    
 beforeloop:
    mov eax, mul_result
    call slen
    mov edx, eax
    cmp edx, dword[temp_len1_for_mul]
    ja swap
    mov eax, mul_result
    call slen
    mov dword[temp_len2], eax
    mov eax, dword[temp_len1_for_mul]
    mov dword[temp_len1], eax
    mov eax, num1_for_mul
    mov ebx, mul_result
    ret
    
swap:
    mov eax, mul_result
    call slen
    mov dword[temp_len1], eax
    mov eax, dword[temp_len1_for_mul]
    mov dword[temp_len2], eax
    mov eax, mul_result
    mov ebx, num1_for_mul
    ret
    
slen:
    push ebx
    mov ebx,eax
nextchar:
    cmp byte [eax], 0
    jz finished
    inc eax
    jmp nextchar
finished:
    sub eax, ebx
    pop ebx
    ret
    
sprint:
    call slen
    mov edx, eax
    mov ebx, 1
    mov eax, 4
    int 80h
    ret
    
    
print_res:
    call sprint
    mov eax, line_split
    mov ecx, line_split
    call sprint
    ret
    
exit:
    mov eax, 1
    mov ebx, 0
    int 80h
    ret
